package com.echo.im.server.netty.processor.impl;

import cn.hutool.core.bean.BeanUtil;
import com.echo.im.common.contant.IMConstant;
import com.echo.im.common.contant.IMRedisKey;
import com.echo.im.common.enums.IMCmdType;
import com.echo.im.common.model.IMHeartbeatInfo;
import com.echo.im.common.model.IMSendInfo;
import com.echo.im.server.netty.context.ChannelAttrKey;
import com.echo.im.server.netty.processor.AbstractMessageProcessor;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.AttributeKey;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.concurrent.TimeUnit;

/**
 *
 * @author echo
 * @date 2024-08-18
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class HeartbeatProcessor extends AbstractMessageProcessor<IMHeartbeatInfo> {
    public static final int HEARTBEAT_INTERVAL = 10;
    private final RedisTemplate<String, Object> redisTemplate;

    /**
     * 1. 快速响应ws
     * 2. 更新channel心跳次数
     * 3. 根据策略刷新延时用户在线状态
     * @param ctx
     * @param data
     */
    @Override
    public void process(ChannelHandlerContext ctx, IMHeartbeatInfo data) {
        // 快速响应ws
        IMSendInfo sendInfo = new IMSendInfo();
        sendInfo.setCmd(IMCmdType.HEART_BEAT.code());
        ctx.channel().writeAndFlush(sendInfo);

        // 更新心跳次数
        AttributeKey<Long> heartBeatAttr = AttributeKey.valueOf(ChannelAttrKey.HEARTBEAT_TIMES);
        Long heartbeatTimes = ctx.channel().attr(heartBeatAttr).get();
        ctx.channel().attr(heartBeatAttr).set(++heartbeatTimes);

        if (heartbeatTimes%HEARTBEAT_INTERVAL == 0){
            // 每心跳10次，用户在线状态续一次命
            AttributeKey<Long> userIdAttr = AttributeKey.valueOf(ChannelAttrKey.USER_ID);
            Long userId = ctx.channel().attr(userIdAttr).get();
            AttributeKey<Integer> terminalAttr = AttributeKey.valueOf(ChannelAttrKey.TERMINAL_TYPE);
            Integer terminal = ctx.channel().attr(terminalAttr).get();
            String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, userId.toString(), terminal.toString());
            redisTemplate.expire(key, IMConstant.ONLINE_TIMEOUT_SECOND, TimeUnit.SECONDS);
        }

        AttributeKey<Long> userIdAttr = AttributeKey.valueOf(ChannelAttrKey.USER_ID);
        Long userId = ctx.channel().attr(userIdAttr).get();
        log.info("心跳,userId:{},{}",userId,ctx.channel().id().asLongText());
    }

    @Override
    public void process(IMHeartbeatInfo data) {

    }

    @Override
    public IMCmdType getCmdType() {
        return IMCmdType.HEART_BEAT;
    }

    @Override
    public IMHeartbeatInfo transForm(Object o) {
        HashMap map = (HashMap) o;
        return BeanUtil.fillBeanWithMap(map, new IMHeartbeatInfo(), false);
    }
}
